home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 2.5)
-
- from base64 import b64encode
- from gtcache import gettext as _
- from threading import RLock
- import os
- import re
- import shutil
- from database import DDBObject, defaultDatabase
- from dl_daemon import daemon, command
- from download_utils import nextFreeFilename, getFileURLPath, filterDirectoryName
- from util import getTorrentInfoHash, returnsUnicode, checkU, returnsFilename, unicodify, checkF, stringify
- from platformutils import FilenameType
- import app
- import config
- import httpclient
- import indexes
- import prefs
- import random
- import views
- import platformutils
- import flashscraper
- import logging
- import traceback
- import templatehelper
- import fileutil
- _downloads = { }
-
- def findHTTPAuth(host, path, realm = None, scheme = None):
- checkU(host)
- checkU(path)
- if realm:
- checkU(realm)
-
- if scheme:
- checkU(scheme)
-
- defaultDatabase.confirmDBThread()
- for obj in views.httpauths:
- if obj.host == host and path.startswith(obj.path):
- if realm is None or obj.realm == realm:
- if scheme is None or obj.authScheme == scheme:
- return obj
- continue
-
-
-
- class HTTPAuthPassword(DDBObject):
-
- def __init__(self, username, password, host, realm, path, authScheme = u'Basic'):
- checkU(username)
- checkU(password)
- checkU(host)
- checkU(realm)
- checkU(path)
- checkU(authScheme)
- oldAuth = findHTTPAuth(host, path, realm, authScheme)
- while oldAuth is not None:
- oldAuth.remove()
- oldAuth = findHTTPAuth(host, path, realm, authScheme)
- self.username = username
- self.password = password
- self.host = host
- self.realm = realm
- self.path = os.path.dirname(path)
- self.authScheme = authScheme
- DDBObject.__init__(self)
-
-
- def getAuthToken(self):
- authString = u':'
- self.confirmDBThread()
- authString = self.username + u':' + self.password
- return b64encode(authString)
-
-
- def getAuthScheme(self):
- self.confirmDBThread()
- return self.authScheme
-
-
- totalUpRate = 0
- totalDownRate = 0
-
- def _getDownloader(dlid):
- return views.remoteDownloads.getItemWithIndex(indexes.downloadsByDLID, dlid)
-
-
- def generateDownloadID():
- dlid = u'download%08d' % random.randint(0, 99999999)
- while _getDownloader(dlid = dlid):
- dlid = u'download%08d' % random.randint(0, 99999999)
- return dlid
-
- generateDownloadID = returnsUnicode(generateDownloadID)
-
- class RemoteDownloader(DDBObject):
- '''Download a file using the downloader daemon.'''
-
- def __init__(self, url, item, contentType = None, channelName = None):
- checkU(url)
- if contentType:
- checkU(contentType)
-
- self.origURL = self.url = url
- self.itemList = [
- item]
- self.dlid = generateDownloadID()
- self.status = { }
- if contentType is None:
- enclosureContentType = item.getFirstVideoEnclosureType()
- if enclosureContentType == u'application/x-bittorrent':
- contentType = enclosureContentType
-
-
- self.contentType = u''
- self.deleteFiles = True
- self.channelName = channelName
- self.manualUpload = False
- DDBObject.__init__(self)
- if contentType is None:
- self.contentType = u''
- else:
- self.contentType = contentType
- if self.contentType == u'':
- self.getContentType()
- else:
- self.runDownloader()
-
-
- def signalChange(self, needsSave = True, needsSignalItem = True):
- if needsSignalItem:
- for item in self.itemList:
- item.signalChange(needsSave = False)
-
-
- DDBObject.signalChange(self, needsSave = needsSave)
-
-
- def onContentType(self, info):
- if not self.idExists():
- return None
-
- if info['status'] == 200:
- self.url = info['updated-url'].decode('ascii', 'replace')
- self.contentType = None
-
- try:
- self.contentType = info['content-type'].decode('ascii', 'replace')
- except:
- self.contentType = None
-
- self.runDownloader()
- else:
- error = httpclient.UnexpectedStatusCode(info['status'])
- self.onContentTypeError(error)
-
-
- def onContentTypeError(self, error):
- if not self.idExists():
- return None
-
- self.status['state'] = u'failed'
- self.status['shortReasonFailed'] = error.getFriendlyDescription()
- self.status['reasonFailed'] = error.getLongDescription()
- self.signalChange()
-
-
- def getContentType(self):
- httpclient.grabHeaders(self.url, self.onContentType, self.onContentTypeError)
-
-
- def initializeDaemon(cls):
- RemoteDownloader.dldaemon = daemon.ControllerDaemon()
-
- initializeDaemon = classmethod(initializeDaemon)
-
- def _getRates(self):
- state = self.getState()
- if state == u'downloading':
- return (self.status.get('rate', 0), self.status.get('upRate', 0))
-
- if state == u'uploading':
- return (0, self.status.get('upRate', 0))
-
- return (0, 0)
-
-
- def updateStatus(cls, data):
- global totalDownRate, totalUpRate, totalDownRate, totalUpRate
- for field in data:
- if field not in ('filename', 'shortFilename', 'channelName', 'metainfo', 'fastResumeData'):
- data[field] = unicodify(data[field])
- continue
-
- self = _getDownloader(dlid = data['dlid'])
- if self is not None:
-
- try:
- if self.status == data:
- return None
- except Exception:
- e = None
- print 'WARNING exception when comparing status: %s' % e
-
- wasFinished = self.isFinished()
- rates = self._getRates()
- totalDownRate -= rates[0]
- totalUpRate -= rates[1]
- if data.has_key('activity') and data['activity']:
- data['activity'] = _(data['activity'])
-
- self.status = data
- if self.isFinished():
- pass
- finished = not wasFinished
- rates = self._getRates()
- totalDownRate += rates[0]
- totalUpRate += rates[1]
- if self.getState() == u'uploading' and not (self.manualUpload) and self.getUploadRatio() > 1.5:
- self.stopUpload()
-
- self.signalChange(needsSignalItem = not finished)
- if finished:
- for item in self.itemList:
- item.onDownloadFinished()
-
-
-
-
- updateStatus = classmethod(updateStatus)
-
- def runDownloader(self):
- flashscraper.tryScrapingURL(self.url, self._runDownloader)
-
-
- def _runDownloader(self, url, contentType = None):
- if not self.idExists():
- return None
-
- if contentType is not None:
- self.contentType = contentType
-
- if url is not None:
- self.url = url
- c = command.StartNewDownloadCommand(RemoteDownloader.dldaemon, self.url, self.dlid, self.contentType, self.channelName)
- c.send()
- _downloads[self.dlid] = self
- else:
- self.status['state'] = u'failed'
- self.status['shortReasonFailed'] = _('File not found')
- self.status['reasonFailed'] = _('Flash URL Scraping Error')
- self.signalChange()
-
-
- def pause(self, block = False):
- if _downloads.has_key(self.dlid):
- c = command.PauseDownloadCommand(RemoteDownloader.dldaemon, self.dlid)
- c.send()
- else:
- self.status['state'] = u'paused'
- self.signalChange()
-
-
- def stop(self, delete):
- if self.getState() in (u'downloading', u'uploading', u'paused'):
- if _downloads.has_key(self.dlid):
- c = command.StopDownloadCommand(RemoteDownloader.dldaemon, self.dlid, delete)
- c.send()
- del _downloads[self.dlid]
-
- elif delete:
- self.delete()
-
- self.status['state'] = u'stopped'
- self.signalChange()
-
-
- def delete(self):
-
- try:
- filename = self.status['filename']
- except KeyError:
- return None
-
-
- try:
- fileutil.delete(filename)
- except:
- logging.warn('Error deleting downloaded file: %s\n%s' % (templatehelper.toUni(stringify(filename)), traceback.format_exc()))
-
- parent = os.path.join(filename, os.path.pardir)
- parent = os.path.normpath(parent)
- moviesDir = config.get(prefs.MOVIES_DIRECTORY)
- if os.path.exists(parent) and os.path.exists(moviesDir) and not platformutils.samefile(parent, moviesDir) and len(os.listdir(parent)) == 0:
-
- try:
- os.rmdir(parent)
- logging.warn('Error deleting empty download directory: %s\n%s' % (templatehelper.toUni(parent), traceback.format_exc()))
-
-
-
-
- def start(self):
- if self.getState() == u'failed':
- if _downloads.has_key(self.dlid):
- del _downloads[self.dlid]
-
- self.dlid = generateDownloadID()
- views.remoteDownloads.recomputeIndex(indexes.downloadsByDLID)
- self.status = { }
- if self.contentType == u'':
- self.getContentType()
- else:
- self.runDownloader()
- self.signalChange()
- elif self.getState() in (u'stopped', u'paused', u'offline'):
- if _downloads.has_key(self.dlid):
- c = command.StartDownloadCommand(RemoteDownloader.dldaemon, self.dlid)
- c.send()
- else:
- self.status['state'] = u'downloading'
- self.restart()
- self.signalChange()
-
-
-
- def migrate(self, directory):
- if _downloads.has_key(self.dlid):
- c = command.MigrateDownloadCommand(RemoteDownloader.dldaemon, self.dlid, directory)
- c.send()
- else:
-
- try:
- shortFilename = self.status['shortFilename']
- except KeyError:
- print "WARNING: can't migrate download because we don't have a shortFilename!\nURL was %s" % self.url
- return None
-
-
- try:
- filename = self.status['filename']
- except KeyError:
- print "WARNING: can't migrate download because we don't have a filename!\nURL was %s" % self.url
- return None
-
- if os.path.exists(filename):
- if 'channelName' in self.status and self.status['channelName'] is not None:
- channelName = filterDirectoryName(self.status['channelName'])
- directory = os.path.join(directory, channelName)
-
-
- try:
- os.makedirs(directory)
- except:
- pass
-
- newfilename = os.path.join(directory, shortFilename)
- if newfilename == filename:
- return None
-
- newfilename = nextFreeFilename(newfilename)
-
- def callback():
- self.status['filename'] = newfilename
- self.signalChange()
-
- fileutil.migrate_file(filename, newfilename, callback)
-
- for i in self.itemList:
- i.migrateChildren(directory)
-
-
-
- def setDeleteFiles(self, deleteFiles):
- self.deleteFiles = deleteFiles
-
-
- def setChannelName(self, channelName):
- if self.channelName is None:
- if channelName:
- checkF(channelName)
-
- self.channelName = channelName
-
-
-
- def remove(self):
- global totalDownRate, totalUpRate
- rates = self._getRates()
- totalDownRate -= rates[0]
- totalUpRate -= rates[1]
- self.stop(self.deleteFiles)
- DDBObject.remove(self)
-
-
- def getType(self):
- '''Get the type of download. Will return either "http" or
- "bittorrent".
- '''
- self.confirmDBThread()
- if self.contentType == u'application/x-bittorrent':
- return u'bittorrent'
- else:
- return u'http'
-
-
- def addItem(self, item):
- if item not in self.itemList:
- self.itemList.append(item)
-
-
-
- def removeItem(self, item):
- self.itemList.remove(item)
- if len(self.itemList) == 0:
- self.remove()
-
-
-
- def getRate(self):
- self.confirmDBThread()
- return self.status.get('rate', 0)
-
-
- def getETA(self):
- self.confirmDBThread()
- return self.status.get('eta', 0)
-
-
- def getStartupActivity(self):
- self.confirmDBThread()
- activity = self.status.get('activity')
- if activity is None:
- return _('starting up')
- else:
- return activity
-
- getStartupActivity = returnsUnicode(getStartupActivity)
-
- def getReasonFailed(self):
- if not self.getState() == u'failed':
- msg = u'getReasonFailed() called on a non-failed downloader'
- raise ValueError(msg)
-
- self.confirmDBThread()
- return self.status['reasonFailed']
-
- getReasonFailed = returnsUnicode(getReasonFailed)
-
- def getShortReasonFailed(self):
- if not self.getState() == u'failed':
- msg = u'getShortReasonFailed() called on a non-failed downloader'
- raise ValueError(msg)
-
- self.confirmDBThread()
- return self.status['shortReasonFailed']
-
- getShortReasonFailed = returnsUnicode(getShortReasonFailed)
-
- def getURL(self):
- self.confirmDBThread()
- return self.url
-
- getURL = returnsUnicode(getURL)
-
- def getState(self):
- self.confirmDBThread()
- return self.status.get('state', u'downloading')
-
- getState = returnsUnicode(getState)
-
- def isFinished(self):
- return self.getState() in (u'finished', u'uploading')
-
-
- def getTotalSize(self):
- self.confirmDBThread()
- return self.status.get(u'totalSize', -1)
-
-
- def getCurrentSize(self):
- self.confirmDBThread()
- return self.status.get(u'currentSize', 0)
-
-
- def getFilename(self):
- self.confirmDBThread()
- return self.status.get('filename', FilenameType(''))
-
- getFilename = returnsFilename(getFilename)
-
- def onRestore(self):
- self.deleteFiles = True
- self.itemList = []
- if self.dlid == 'noid':
- self.dlid = generateDownloadID()
-
- self.status['rate'] = 0
- self.status['upRate'] = 0
- self.status['eta'] = 0
-
-
- def getUploadRatio(self):
- size = self.getCurrentSize()
- if size == 0:
- return 0
-
- return self.status.get('uploaded', 0) * 1024 * 1024 / size
-
-
- def restartIfNeeded(self):
- if self.getState() in (u'downloading', u'offline'):
- self.restart()
-
- if self.getState() in u'uploading':
- if self.manualUpload or self.getUploadRatio() < 1.5:
- self.restart()
- else:
- self.stopUpload()
-
-
-
- def restart(self):
- if len(self.status) == 0 or self.status.get('dlerType') is None:
- if self.contentType == u'':
- self.getContentType()
- else:
- self.runDownloader()
- else:
- _downloads[self.dlid] = self
- c = command.RestoreDownloaderCommand(RemoteDownloader.dldaemon, self.status)
- c.send()
-
-
- def startUpload(self):
- if self.getState() != u'finished' or self.getType() != u'bittorrent':
- return None
-
- self.manualUpload = True
- if _downloads.has_key(self.dlid):
- c = command.StartDownloadCommand(RemoteDownloader.dldaemon, self.dlid)
- c.send()
- else:
- self.status['state'] = u'uploading'
- self.restart()
- self.signalChange()
-
-
- def stopUpload(self):
- if self.getState() != u'uploading':
- return None
-
- if _downloads.has_key(self.dlid):
- c = command.StopUploadCommand(RemoteDownloader.dldaemon, self.dlid)
- c.send()
- del _downloads[self.dlid]
-
- self.status['state'] = u'finished'
- self.signalChange()
-
-
-
- def cleanupIncompleteDownloads():
- downloadDir = os.path.join(config.get(prefs.MOVIES_DIRECTORY), 'Incomplete Downloads')
- if not os.path.exists(downloadDir):
- return None
-
- filesInUse = set()
- views.remoteDownloads.confirmDBThread()
- for downloader in views.remoteDownloads:
- if downloader.getState() in ('downloading', 'paused', 'offline'):
- filename = downloader.getFilename()
- if len(filename) > 0:
- if not os.path.isabs(filename):
- filename = os.path.join(downloadDir, filename)
-
- filesInUse.add(filename)
-
- len(filename) > 0
-
- for f in os.listdir(downloadDir):
- f = os.path.join(downloadDir, f)
- if f not in filesInUse:
-
- try:
- if os.path.isfile(f):
- os.remove(f)
- elif os.path.isdir(f):
- shutil.rmtree(f)
-
- continue
-
-
-
- def restartDownloads():
- views.remoteDownloads.confirmDBThread()
- for downloader in views.remoteDownloads:
- downloader.restartIfNeeded()
-
-
-
- def killUploaders(*args):
- torrent_limit = config.get(prefs.UPSTREAM_TORRENT_LIMIT)
- while views.autoUploads.len() > torrent_limit:
- views.autoUploads[0].stopUpload()
-
-
- def configChangeUploaders(key, value):
- if key == prefs.UPSTREAM_TORRENT_LIMIT.key:
- killUploaders()
-
-
-
- def limitUploaders():
- views.autoUploads.addAddCallback(killUploaders)
- config.addChangeCallback(configChangeUploaders)
- killUploaders()
-
-
- def startupDownloader():
- '''Initialize the downloaders.
-
- This method currently does 2 things. It deletes any stale files self in
- Incomplete Downloads, then it restarts downloads that have been restored
- from the database. It must be called before any RemoteDownloader objects
- get created.
- '''
- cleanupIncompleteDownloads()
- RemoteDownloader.initializeDaemon()
- limitUploaders()
- restartDownloads()
-
-
- def shutdownDownloader(callback = None):
- if hasattr(RemoteDownloader, 'dldaemon') and RemoteDownloader.dldaemon is not None:
- RemoteDownloader.dldaemon.shutdownDownloaderDaemon(callback = callback)
-
-
-
- def lookupDownloader(url):
- return views.remoteDownloads.getItemWithIndex(indexes.downloadsByURL, url)
-
-
- def getExistingDownloaderByURL(url):
- downloader = lookupDownloader(url)
- return downloader
-
-
- def getExistingDownloader(item):
- downloader = lookupDownloader(item.getURL())
- if downloader:
- downloader.addItem(item)
-
- return downloader
-
-
- def getDownloader(item):
- existing = getExistingDownloader(item)
- if existing:
- return existing
-
- url = item.getURL()
- channelName = platformutils.unicodeToFilename(item.getChannelTitle(True))
- if not channelName:
- channelName = None
-
- if url.startswith(u'file://'):
- path = getFileURLPath(url)
-
- try:
- getTorrentInfoHash(path)
- except ValueError:
- raise ValueError("Don't know how to handle %s" % url)
- except IOError:
- return None
-
- return RemoteDownloader(url, item, u'application/x-bittorrent', channelName = channelName)
- else:
- return RemoteDownloader(url, item, channelName = channelName)
-
-